/**
 * 本地缓存工具
 * 支持过期时间、批量操作、命名空间等高级功能
 */

interface CacheItem<T = any> {
  data: T
  timestamp: number
  expireTime?: number // 过期时间戳
}

interface CacheOptions {
  expireTime?: number // 过期时间（毫秒）
  namespace?: string // 命名空间
}

class CacheManager {
  private defaultNamespace = 'sbook_cache'
  private memoryCache = new Map<string, CacheItem>()

  /**
   * 生成缓存键名
   */
  private getKey(key: string, namespace?: string): string {
    const ns = namespace || this.defaultNamespace
    return `${ns}:${key}`
  }

  /**
   * 检查缓存是否过期
   */
  private isExpired(item: CacheItem): boolean {
    if (!item.expireTime)
      return false
    return Date.now() > item.expireTime
  }

  /**
   * 设置缓存
   */
  set<T>(key: string, data: T, options: CacheOptions = {}): void {
    const { expireTime, namespace } = options
    const fullKey = this.getKey(key, namespace)

    const item: CacheItem<T> = {
      data,
      timestamp: Date.now(),
      expireTime: expireTime ? Date.now() + expireTime : undefined,
    }

    try {
      // 优先使用内存缓存，提高读取速度
      this.memoryCache.set(fullKey, item)

      // 同时持久化到本地存储，防止内存丢失
      uni.setStorageSync(fullKey, JSON.stringify(item))
    }
    catch (error) {
      console.warn('缓存设置失败:', error)
      // 如果持久化失败，至少保留内存缓存
    }
  }

  /**
   * 获取缓存
   */
  get<T>(key: string, namespace?: string): T | null {
    const fullKey = this.getKey(key, namespace)

    // 先尝试从内存缓存获取
    let item = this.memoryCache.get(fullKey)

    if (!item) {
      // 内存缓存没有，尝试从本地存储获取
      try {
        const stored = uni.getStorageSync(fullKey)
        if (stored) {
          item = JSON.parse(stored)
          // 重新放入内存缓存
          this.memoryCache.set(fullKey, item)
        }
      }
      catch (error) {
        console.warn('缓存读取失败:', error)
        return null
      }
    }

    if (!item)
      return null

    // 检查是否过期
    if (this.isExpired(item)) {
      this.remove(key, namespace)
      return null
    }

    return item.data as T
  }

  /**
   * 删除缓存
   */
  remove(key: string, namespace?: string): void {
    const fullKey = this.getKey(key, namespace)

    // 从内存缓存删除
    this.memoryCache.delete(fullKey)

    // 从本地存储删除
    try {
      uni.removeStorageSync(fullKey)
    }
    catch (error) {
      console.warn('缓存删除失败:', error)
    }
  }

  /**
   * 检查缓存是否存在且未过期
   */
  has(key: string, namespace?: string): boolean {
    const data = this.get(key, namespace)
    return data !== null
  }

  /**
   * 清除指定命名空间的所有缓存
   */
  clearNamespace(namespace: string): void {
    const prefix = `${namespace}:`

    // 清除内存缓存
    for (const key of this.memoryCache.keys()) {
      if (key.startsWith(prefix)) {
        this.memoryCache.delete(key)
      }
    }

    // 清除本地存储
    try {
      const storageInfo = uni.getStorageInfoSync()
      storageInfo.keys.forEach((key) => {
        if (key.startsWith(prefix)) {
          uni.removeStorageSync(key)
        }
      })
    }
    catch (error) {
      console.warn('清除命名空间缓存失败:', error)
    }
  }

  /**
   * 清除所有缓存
   */
  clear(): void {
    // 清除内存缓存
    this.memoryCache.clear()

    try {
      // 清除本地存储中的所有缓存
      const storageInfo = uni.getStorageInfoSync()
      storageInfo.keys.forEach((key) => {
        if (key.includes('cache:')) {
          uni.removeStorageSync(key)
        }
      })
    }
    catch (error) {
      console.warn('清除所有缓存失败:', error)
    }
  }

  /**
   * 获取缓存信息（大小、数量等）
   */
  getInfo(namespace?: string): { count: number, size: string } {
    const prefix = namespace ? `${namespace}:` : `${this.defaultNamespace}:`
    let count = 0
    let totalSize = 0

    try {
      const storageInfo = uni.getStorageInfoSync()
      storageInfo.keys.forEach((key) => {
        if (key.startsWith(prefix)) {
          count++
          const data = uni.getStorageSync(key)
          totalSize += new Blob([data]).size
        }
      })
    }
    catch (error) {
      console.warn('获取缓存信息失败:', error)
    }

    return {
      count,
      size: this.formatBytes(totalSize),
    }
  }

  /**
   * 格式化字节数
   */
  private formatBytes(bytes: number): string {
    if (bytes === 0)
      return '0 B'
    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`
  }

  /**
   * 批量设置缓存
   */
  setBatch<T extends Record<string, any>>(data: T, options: CacheOptions = {}): void {
    Object.entries(data).forEach(([key, value]) => {
      this.set(key, value, options)
    })
  }

  /**
   * 批量获取缓存
   */
  getBatch<T extends Record<string, any>>(keys: string[], namespace?: string): Partial<T> {
    const result: Partial<T> = {}

    keys.forEach((key) => {
      const value = this.get(key, namespace)
      if (value !== null) {
        result[key as keyof T] = value
      }
    })

    return result
  }

  /**
   * 获取或设置缓存（如果不存在则设置）
   */
  async getOrSet<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: CacheOptions = {},
  ): Promise<T> {
    const cached = this.get<T>(key, options.namespace)

    if (cached !== null) {
      return cached
    }

    try {
      const data = await fetcher()
      this.set(key, data, options)
      return data
    }
    catch (error) {
      // 如果获取数据失败，尝试返回过期的缓存（如果存在）
      const staleData = this.getStale<T>(key, options.namespace)
      if (staleData !== null) {
        console.warn('使用过期缓存数据:', key)
        return staleData
      }
      throw error
    }
  }

  /**
   * 获取过期的缓存数据
   */
  private getStale<T>(key: string, namespace?: string): T | null {
    const fullKey = this.getKey(key, namespace)

    try {
      const stored = uni.getStorageSync(fullKey)
      if (stored) {
        const item = JSON.parse(stored) as CacheItem<T>
        return item.data
      }
    }
    catch (error) {
      console.warn('获取过期缓存失败:', error)
    }

    return null
  }
}

// 创建全局缓存管理器实例
const cacheManager = new CacheManager()

// 导出便捷方法和类
export { cacheManager, CacheManager }
export default cacheManager

// 便捷的缓存方法
export const cache = {
  set: <T>(key: string, data: T, expireTime?: number) =>
    cacheManager.set(key, data, { expireTime }),

  get: <T>(key: string) =>
    cacheManager.get<T>(key),

  remove: (key: string) =>
    cacheManager.remove(key),

  has: (key: string) =>
    cacheManager.has(key),

  clear: () =>
    cacheManager.clear(),

  clearNamespace: (namespace: string) =>
    cacheManager.clearNamespace(namespace),

  getInfo: (namespace?: string) =>
    cacheManager.getInfo(namespace),

  getOrSet: <T>(key: string, fetcher: () => Promise<T>, expireTime?: number) =>
    cacheManager.getOrSet(key, fetcher, { expireTime }),
}

// 预定义的缓存命名空间
export const CACHE_NAMESPACES = {
  NOVEL: 'novel',
  CHAPTER: 'chapter',
  COMMENT: 'comment',
  USER: 'user',
  SEARCH: 'search',
} as const

// 预定义的缓存时间
export const CACHE_TIMES = {
  SHORT: 5 * 60 * 1000, // 5分钟
  MEDIUM: 15 * 60 * 1000, // 15分钟
  LONG: 30 * 60 * 1000, // 30分钟
  VERY_LONG: 60 * 60 * 1000, // 1小时
  DAY: 24 * 60 * 60 * 1000, // 1天
} as const
